package sbc.group1.lab1.common;

import java.awt.Color;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Set;

public class Car implements Coatable, Serializable {
    public final static int NUM_WHEELS = 4;
    
    private Order order;
    private CarBody carBody;
    private Engine engine;
    private ArrayList<Wheel> wheels = new ArrayList<Wheel>(NUM_WHEELS); 
    private final int assemblerId;
    private int logisticianId;
    
    private boolean markedAsFinished = false;
    private boolean markedAsDefect = false;
    
    private TestStatus defectTestStatus = TestStatus.NOT_TESTED;
    private TestStatus completenessTestStatus = TestStatus.NOT_TESTED;

    public Car(CarBody carBody, Engine engine, Set<Wheel> wheels, 
           Assembler assembler, Order order) {
        this.order=order;
        this.assemblerId=assembler.getId();
        this.carBody=carBody;
        this.engine=engine;
        if (wheels.size() != NUM_WHEELS) {
            throw new IllegalArgumentException();
        }else {
            this.wheels = new ArrayList<Wheel>(wheels);
        }
    }
    public Car(CarBody carBody, Engine engine, Set<Wheel> wheels, 
            Assembler assembler) {
        this(carBody, engine, wheels, assembler, null);
    }

    @Override
    public void coat(Color color, Coater coater) {
        carBody.coat(color, coater);
    }

    @Override
    public int coatedBy() {
        return carBody.coatedBy();
    }

    @Override
    public Color getColor() {
        return carBody.getColor();
    }

    @Override
    public boolean isCoated() {
        return carBody.isCoated();
    }
    
    public int getAssemblerId() {
        return assemblerId; 
    }
    
    public Engine getEngine() {
        return engine;
    }
    
    public CarBody getCarBody() {
        return carBody;
    }
    
    public Collection<Wheel> getWheels() {
        return new ArrayList<Wheel>(wheels);
    }
    
    public boolean isManufacturingDone() {
        return isCoated();
    }
    
    public void markAsFinished(Logistician logistician) {
            this.logisticianId = logistician.getId();
            this.markedAsFinished  = true;
    }
    
    public boolean isMarkedAsFinished() {
        return markedAsFinished;
    }
    
    public void markAsDefect() {
        markedAsDefect=true;
    }
    
    public boolean isMarkedAsDefect() {
        return markedAsDefect;
    }
    
    public int getLogisticianId() {
        return logisticianId;
    }
    
    public String toString() {
        return String.format("%s[assembler=%s, logistician=%s, order=%s, %s, %s, %s]", 
                this.getClass().getSimpleName(),
                getAssemblerId(),
                getLogisticianId(),
                getOrder()==null ? null : getOrder().getId(),
                carBody.toString(),
                engine.toString(),
                wheels.toString());
    }

    public boolean isDefect() {
        try {
            if (carBody.isDefect() || engine.isDefect()) {
                return true;
            }else {
                for (Wheel wheel : wheels) {
                    if (wheel.isDefect()) {
                        return true;
                    }
                }
            }
        }catch(NullPointerException e) {
            return true;
        }
        return false;
    }
    public boolean isComplete() {
       if (getCarBody() == null) {
           return false;
       }else if (getEngine()==null) {
           return false;
       }else if (getWheels().size()!=NUM_WHEELS) {
           return false;
       }else if (!isCoated()) {
           return false;
       }else {
           return true;
       }
    }
    
    
    public TestStatus getCompletenessTestStatus() {
        return completenessTestStatus;
    }
    
    public TestStatus getDefectTestStatus() {
        return defectTestStatus;
    }
    
    public boolean isCompletelyTested() {
        return completenessTestStatus!=TestStatus.NOT_TESTED && 
            defectTestStatus!=TestStatus.NOT_TESTED;
    }
    
    public void setDefectTestStatus(TestStatus defectTestStatus) {
        this.defectTestStatus = defectTestStatus;
    }
    
    public void setCompletenessTestStatus(TestStatus completenessTestStatus) {
        this.completenessTestStatus = completenessTestStatus;
    }
    
    public Order getOrder() {
        return order;
    }
    @Override
    public boolean equals(Object o) {
        if (o!=null) {
           if (this.engine==null || !this.engine.hasId()) {
               return super.equals(o);
           }
           if (o instanceof Car) {
               Car that = (Car) o;
               if (that.engine==null) {
                   return false;
               }
               if (that.engine.hasId()) {
                   return that.engine.getId()==this.engine.getId();
               }else {
                   return super.equals(o);
               }
           }
        }
        return false;
    }
}
